﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace LibrarySync2.Common.Extensions
{
    public static class DirectoryInfoExtensionMethods
    {
        public static DirectoryInfo CreateSubdirectories(this DirectoryInfo toCreate, string localRoot, string path, bool includeMetadata)
        {
            var result = new DirectoryInfo(toCreate.FullName);
            var localDirInfo = new DirectoryInfo(localRoot);
            if (!localDirInfo.Exists)
                throw new ArgumentException("Argument localRoot does not exist.");

            var reconstructedPath = string.Empty;
            var pathBits = path.Split(Path.DirectorySeparatorChar);
            foreach (var bit in pathBits)
            {
                if (string.IsNullOrEmpty(bit))
                    continue;

                reconstructedPath = string.Concat(reconstructedPath, Path.DirectorySeparatorChar.ToString(), bit);

                var updatedPath = string.Concat(result.FullName, Path.DirectorySeparatorChar.ToString(), bit);
                var existingDirInfo = new DirectoryInfo(updatedPath);
                if (existingDirInfo.Exists)
                {
                    result = existingDirInfo;
                    continue;
                }    

                result.CreateSubdirectory(bit);
                result = new DirectoryInfo(updatedPath);

                if (!includeMetadata)
                    continue;

                var localPath = string.Concat(localDirInfo.FullName, Path.DirectorySeparatorChar.ToString(), reconstructedPath);
                var localCorrespondingDirInfo = new DirectoryInfo(localPath);
                if (!localDirInfo.Exists)
                    throw new ApplicationException("Path is not respective of filesystem reality.");

                CopyNonMediaFilesTo(localCorrespondingDirInfo, result);
            }

            return result;
        }

        public static void CopyNonMediaFilesTo(this DirectoryInfo source, DirectoryInfo destination)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (!source.Exists)
                throw new ArgumentException("source does not exist", "source");
            if (destination == null)
                throw new ArgumentNullException("destination");
            if (!destination.Exists)
                throw new ArgumentException("destination does not exist", "destination");

            foreach (var nonMediaFile in source.GetFiles().ToList<FileInfo>().FindAll(fi => !fi.IsMediaFile()))
            {
                nonMediaFile.CopyTo(string.Concat(destination.FullName, Path.DirectorySeparatorChar.ToString(), nonMediaFile.Name));
            }
        }

        public static long CalculateSizeFromRoot(this DirectoryInfo directory, string root)
        {
            if (string.IsNullOrEmpty(root))
                throw new ArgumentNullException("root");
            if (!directory.FullName.StartsWith(root))
                throw new ArgumentException("The directory must start with the provided root.");

            if (directory.FullName.Equals(root, StringComparison.OrdinalIgnoreCase))
                return 0L;

            long currentDirectorySize = 0L;
            directory.GetFiles().ToList<FileInfo>().ForEach(f => currentDirectorySize += f.Length);

            return currentDirectorySize += directory.Parent.CalculateSizeFromRoot(root);
        }
    }
}
